#ifndef __LOGGER
#define __LOGGER

#include<cstdio>
#include<vector>
#include<string>
#include<ctime>
#include"StandardLibrary.h"

namespace Custom
{
	using std::vector;
	using std::string;

	enum LogLevel
	{
		Unknown = 0,
		Debug = 1,
		Info = 2,
		Stats = 4,
		DebugInfo = 3,
		All = 7
	};

	double ElapsedTime(const clock_t &startTime)
	{
		return (double)(clock()-startTime)/CLOCKS_PER_SEC;
	}

	class Logger
	{
	private:
		class LogFile
		{
		private:
			string Filename;
			FILE *File;
		public:
			LogLevel Level;
			LogFile(const string &fname,LogLevel lvl = LogLevel::All) : Filename(fname) ,
				Level(lvl) , File(0)
			{
			}
			LogFile(FILE *file,LogLevel lvl = LogLevel::All) : Level(lvl) , File(file) ,
				Filename("")
			{
			}

			~LogFile()
			{
				if (File && Filename!="")
					fclose(File);
			}
			void Log(const char *s)
			{
				time_t now_ticks;
				time(&now_ticks);
				tm *now_time = localtime(&now_ticks);
				bool alreadyOpen = (File != 0);
				if (!alreadyOpen)
					File = fopen(Filename.c_str(),"a");
				if (File == 0)
					throw exception(("nie moge otworzyc pliku: "+Filename).c_str());
				fprintf(File,"%.2d:%.2d:%.2d : %s\n",now_time->tm_hour,now_time->tm_min,now_time->tm_sec,s);
				if (File && !alreadyOpen)
				{
					fclose(File);
					File = 0;
				}
				
			}
		};
		vector<LogFile> Logs;
		char Buffer[3000];
	public:
		Logger(const string &fname,LogLevel lvl = LogLevel::All) 
		{
			Logs.push_back(LogFile(fname,lvl));
		}

		Logger(FILE *file,LogLevel lvl = LogLevel::All)
		{
			Logs.push_back(LogFile(file,lvl));
		}

		Logger() {}

		void AddLog(const string &fname,LogLevel lvl = LogLevel::All)
		{
			Logs.push_back(LogFile(fname,lvl));
		}

		void AddLog(FILE *file,LogLevel lvl = LogLevel::All)
		{
			Logs.push_back(LogFile(file,lvl));
		}

		static string DefaultLogName()
		{
			time_t now = time(0);
			tm *today = localtime(&now);
			char buffer[30];
			sprintf(buffer,"%.4d-%.2d-%.2d.log",today->tm_year+1900,today->tm_mon+1,today->tm_mday);
			return buffer;
		}


		void Log(LogLevel lvl,const char *s)
		{
			for (int i=0;i<Logs.size();++i)
				if (lvl&Logs[i].Level)
					Logs[i].Log(s);
		}

		template<class T1>
		void Log(LogLevel lvl,const char *s,const T1 &t1)
		{
			sprintf(Buffer,s,t1);
			Log(lvl,Buffer);
		}
		template<class T1,class T2>
		void Log(LogLevel lvl,const char *s,const T1 &t1,const T2 &t2)
		{
			sprintf(Buffer,s,t1,t2);
			Log(lvl,Buffer);
		}
		template<class T1,class T2,class T3>
		void Log(LogLevel lvl,const char *s,const T1 &t1,const T2 &t2,const T3 &t3)
		{
			sprintf(Buffer,s,t1,t2,t3);
			Log(lvl,Buffer);
		}
		template<class T1,class T2,class T3,class T4>
		void Log(LogLevel lvl,const char *s,const T1 &t1,const T2 &t2,const T3 &t3,const T4 &t4)
		{
			sprintf(Buffer,s,t1,t2,t3,t4);
			Log(lvl,Buffer);
		}
		template<class T1,class T2,class T3,class T4,class T5>
		void Log(LogLevel lvl,const char *s,const T1 &t1,const T2 &t2,const T3 &t3,const T4 &t4,const T5 &t5)
		{
			sprintf(Buffer,s,t1,t2,t3,t4,t5);
			Log(lvl,Buffer);
		}
		template<class T1,class T2,class T3,class T4,class T5,class T6>
		void Log(LogLevel lvl,const char *s,const T1 &t1,const T2 &t2,const T3 &t3,const T4 &t4,const T5 &t5,const T6 &t6)
		{
			sprintf(Buffer,s,t1,t2,t3,t4,t5,t6);
			Log(lvl,Buffer);
		}

		void Log(const char *s)
		{
			Log(LogLevel::All,s);
		}

		template<class T1>
		void Log(const char *s,const T1 &t1)
		{
			sprintf(Buffer,s,t1);
			Log(Buffer);
		}
		template<class T1,class T2>
		void Log(const char *s,const T1 &t1,const T2 &t2)
		{
			sprintf(Buffer,s,t1,t2);
			Log(Buffer);
		}
		template<class T1,class T2,class T3>
		void Log(const char *s,const T1 &t1,const T2 &t2,const T3 &t3)
		{
			sprintf(Buffer,s,t1,t2,t3);
			Log(Buffer);
		}
		template<class T1,class T2,class T3,class T4>
		void Log(const char *s,const T1 &t1,const T2 &t2,const T3 &t3,const T4 &t4)
		{
			sprintf(Buffer,s,t1,t2,t3,t4);
			Log(Buffer);
		}
		template<class T1,class T2,class T3,class T4,class T5>
		void Log(const char *s,const T1 &t1,const T2 &t2,const T3 &t3,const T4 &t4,const T5 &t5)
		{
			sprintf(Buffer,s,t1,t2,t3,t4,t5);
			Log(Buffer);
		}
		template<class T1,class T2,class T3,class T4,class T5,class T6>
		void Log(const char *s,const T1 &t1,const T2 &t2,const T3 &t3,const T4 &t4,const T5 &t5,const T6 &t6)
		{
			sprintf(Buffer,s,t1,t2,t3,t4,t5,t6);
			Log(Buffer);
		}

	};


}


#endif